
import axios from "axios";
import { HTTP_CODE, IExecutor, defaultExecutor, IMethod, METHOD, IRequestOptions, defaultRequestOptions, IContentType, CONTENT_TYPE } from "./val";
import message from "../message";
import storage from "../storage/storage";
import config from '@/config';
import utils from '../utils';
/**
 * 上传下载 参数对象类型
 */
interface IHttpLoad {
    /**
     * 参数
     */
    params?: object;
    /**
     * 进度回调
     * @param val 进度信息对象
     * @param percentage 百分比
     */
    progress?: (val: object, percentage: number) => void;
    /**
     * 是否显示 提示信息
     */
    isToast?: boolean;
}
/**
 * 上传下载 默认参数
 */
const HttpLoadDefault: IHttpLoad = {
    params: {},
    progress: (val: any, percentage: any) => false,
    isToast: true
};

class Http {
    /**
     * 请求方式
     */
    public method: IMethod = METHOD;
    /**
     * 数据提交方式
     */
    public contentType: IContentType = CONTENT_TYPE;
    private apiBaseUrl: string = "";
    constructor(baseUrl: string) {
        this.apiBaseUrl = baseUrl;
    }
    /**
     * get请求
     * @param url 地址
     * @param params 参数
     * @param contentType 数据提交方式
     * @param isToast 是否显示信息
     */
    public Get(url: string = '', params = {}, contentType = CONTENT_TYPE.json, isToast = true): Promise<any> {
        return this.CreateRequest(url, { params, method: "get", contentType, isToast });
    }
    /**
     * post请求
     * @param url 地址
     * @param params 参数
     * @param contentType 数据提交方式
     * @param isToast 是否显示信息
     */
    public Post(url: string = '', params = {}, contentType = CONTENT_TYPE.json, isToast = true): Promise<any> {
        return this.CreateRequest(url, { params, method: "post", contentType, isToast });
    }
    /**
     * delete请求
     * @param url 地址
     * @param params 参数
     * @param contentType 数据提交方式
     * @param isToast 是否显示信息
     */
    public Delete(url: string = '', params = {}, contentType = CONTENT_TYPE.json, isToast = true): Promise<any> {
        return this.CreateRequest(url, { params, method: "delete", contentType, isToast });
    }
    /**
     * put请求
     * @param url 地址
     * @param params 参数
     * @param contentType 数据提交方式
     * @param isToast 是否显示信息
     */
    public Put(url: string = '', params = {}, contentType = CONTENT_TYPE.json, isToast = true): Promise<any> {
        return this.CreateRequest(url, { params, method: "put", contentType, isToast });
    }
    /**
     * patch请求
     * @param url 地址
     * @param params 参数
     * @param contentType 数据提交方式
     * @param isToast 是否显示信息
     */
    public Patch(url: string = '', params = {}, contentType = CONTENT_TYPE.json, isToast = true): Promise<any> {
        return this.CreateRequest(url, { params, method: "patch", contentType, isToast });
    }
    /**
     * head请求
     * @param url 地址
     * @param params 参数
     * @param contentType 数据提交方式
     * @param isToast 是否显示信息
     */
    public Head(url: string = '', params = {}, contentType = CONTENT_TYPE.json, isToast = true): Promise<any> {
        return this.CreateRequest(url, { params, method: "head", contentType, isToast });
    }
    /**
     * options请求
     * @param url 地址
     * @param params 参数
     * @param contentType 数据提交方式
     * @param isToast 是否显示信息
     */
    public Options(url: string = '', params = {}, contentType = CONTENT_TYPE.json, isToast = true): Promise<any> {
        return this.CreateRequest(url, { params, method: "options", contentType, isToast });
    }
    /**
     * 上传文件
     */
    public upload(url: string = '', { params = {}, progress = (val: any, percentage: any) => false, isToast = true }: IHttpLoad = HttpLoadDefault) {
        return new Promise((resolve, reject) => {
            const httpConfig: any = {
                headers: { "Content-Type": CONTENT_TYPE.data },
                onUploadProgress: (progressEvent: any) => {
                    let percentage = (progressEvent.loaded / progressEvent.total) * 100;
                    percentage = parseFloat(percentage.toFixed(2));
                    // 对原生进度事件的处理
                    progress(progressEvent, percentage);
                }
            };
            const param = new FormData();
            type paramType = keyof typeof params;
            Object.keys(params).map((key: any) => {
                param.append(key, params[key as paramType]);
            });
            axios.post(this.apiBaseUrl + url, param, httpConfig).then((response: any) => {
                // 对响应数据做点什么
                message.loadingHide();
                this.ResponseHandle(response.data, { resolve, reject, isToast });
            }).catch((err: any) => {
                message.loadingHide();
                if (isToast) {
                    message.error('网络繁忙，请稍后重试');
                }
                reject(err);
            });
        });
    }
    /*
     * 下载文件
     */
    public download(url = '', { params = {}, progress = (val: any, percentage: any) => false, isToast = true }: IHttpLoad = HttpLoadDefault) {
        return new Promise((resolve, reject) => {
            const httpConfig = {
                responseType: 'blob',
                onDownloadProgress: (progressEvent: any) => {
                    let percentage = (progressEvent.loaded / progressEvent.total) * 100;
                    percentage = parseFloat(percentage.toFixed(2));
                    // 对原生进度事件的处理
                    progress(progressEvent, percentage);
                },
            };
            axios.post(this.apiBaseUrl + url, params, httpConfig).then((response: any) => {
                // 对响应数据做点什么
                message.loadingHide();
                if (response.data instanceof Object) {
                    this.ResponseHandle(response.data, { resolve, reject, isToast });
                } else {
                    resolve(response.data);
                }
            }).catch((err: any) => {
                message.loadingHide();
                if (isToast) {
                    message.error('网络繁忙，请稍后重试')
                }
                reject(err);
            });
        });
    }
    /**
     * 创建一个请求
     */
    private CreateRequest(url: string = '', { params = {}, method = "get", contentType = CONTENT_TYPE.json, isToast = true }: IRequestOptions = defaultRequestOptions): Promise<any> {
        if (contentType === CONTENT_TYPE.form) {
            const form = new FormData();
            const keys = Object.keys(params);
            keys.forEach((key: any) => {
                form.append(key, params[key]);
            });
            params = form;
        }
        return new Promise((resolve: any, reject: any) => {
            axios.request({
                url: this.apiBaseUrl + url,
                method,
                data: params,
                headers: {
                    "Content-Type": contentType
                },
                responseType: "json", // 表示服务器响应的数据类型，可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
            }).then((response: any) => {
                // 对响应数据做点什么
                message.loadingHide();
                if (utils.empty(response.data)) {
                    if (config.debug) {
                        console.error('网络拥堵，请稍后重试');
                    }
                    message.error('网络拥堵，请稍后重试');
                } else {
                    this.ResponseHandle(response.data, { resolve, reject, isToast });
                }
            }).catch((err: any) => {
                if (config.debug) {
                    console.error(err);
                }
                message.loadingHide();
                if (isToast) {
                    message.error('网络繁忙，请稍后重试');
                }
                reject(err);
            });
        });
    }
    /**
     * 处理响应数据
     */
    private ResponseHandle(data: any, { resolve = (val: any) => '', reject = (val: any) => '', isToast = true }: IExecutor = defaultExecutor) {
        switch (data.code) {
            case HTTP_CODE.SUCCESS:
                if (isToast) {
                    message.success(data.message);
                }
                resolve(data.data);
                break;
            case HTTP_CODE.ERROR:
                if (isToast) {
                    message.error(data.message);
                }
                reject(data.message);
                break;
            case HTTP_CODE.NOAUTH:
                message.alert(data.message, { title: '提示' });
                break;
            case HTTP_CODE.LOGIN:
                message.alert(data.message, { title: "登录提示" }).then(() => {
                    storage.clear();
                    window.location.href = config.urlRoot + window.CONFIG.loginPage;
                });
                break;
            case HTTP_CODE.RELOGIN:
                message.alert(data.message, { title: "登录提示" }).then(() => {
                    storage.clear();
                    window.location.href = config.urlRoot + window.CONFIG.loginPage;
                });
                break;
            default:
                if (isToast) {
                    message.error("数据解析失败");
                }
                reject(data.message);
                break;
        }
    }

}

const http: Http = new Http(config.host + config.apiPath + config.servicePath);
export default http;
export const loginHttp = new Http(config.host + config.apiPath);
export const pHttp = new Http(config.host + config.apiPath);

